﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using Microsoft.Office.Server.ActivityFeed;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web;
using System.Data;
using System.Xml;
using System.IO;
using System.Globalization;
using System.Security.Principal;
using System.Reflection;

namespace Square.Activity
{
    public enum SquareActivities
    {
        MemoAll,
        SquareMemoWrite,            //글작성
        SquareMemoCommentWrite,     //댓글 작성
        SquareMemoShareWrite,       //공유글 작성
        SquareMemoGroupWrite,       //그룹글 작성
        PeopleAll,
        SquarePeopleRequest,        //동료요청
        SquarePeopleAccept,         //요청수락
        SquarePeopleGroupCreate,    //동료그룹생성
        SquarePeopleGroupAddPeople, //그룹에 동료 추가
        DocAll,
        SquareDocUpload,            //문서업로드
        SquareDocFolderCreate,      //폴더생성
        SquareDocFolderPermission,  //폴더권한변경
        SquareDocMove,              //문서이동
        SquareDocCopy,              //문서복사
        SquareDocItemRemove,        //문서(폴더) 삭제
        SquareDocFolderRename       //폴더명변경
    }

    public class SquareActivityHelper
    {
        private ActivityApplication actApp = null;
        private ActivityManager actMgr = null;
        private UserProfile curUserProfile = null;
        private ActivityType squareActType = null;
        private ActivityTemplate squareActTemplate = null;
        private List<ActivityEvent> activityEvents = null;
        private Microsoft.Office.Server.UserProfiles.UserProfileManager pm = null;

        public SquareActivityHelper()
        {
        }

        public bool SaveActivity(Page page, SquareActivities sType, string strValue)
        {
            bool ret = false;

            if (!sType.ToString().Contains("All"))
            {
                if(SetActMgr(page))
                {
                    activityEvents = new List<ActivityEvent>();
                    activityEvents.Add(GenerateActivityEvent(page, MakeTypeMessage(sType, strValue), sType));

                    MulticastPublishedEvents(activityEvents);
                    ret = true;
                }
            }
            return ret;
        }

        public DataSet GetActivity(Page page, SquareActivities sType)
        {
            DataSet ds = new DataSet();

            DataTable dt = CreateReturnData(page,sType);
            if (dt != null)
            {
                DataView dv = dt.DefaultView;
                dv.Sort = "ActivityDate DESC, ActivityTime DESC";

                ds.Tables.Add(dv.ToTable());
            }
            return ds;
        }

        private string MakeTypeMessage(SquareActivities sType, string strValue)
        {
            return strValue;
        }

        private DataTable CreateReturnData(Page page, SquareActivities sType)
        {
            DataTable retDT = null;
            if (SetActMgr(page))
            {
                var activitiesForMe = actMgr.GetActivitiesForMe();
                var activitiesByMe = actMgr.GetActivitiesByMe();
                //var activitiesAdministrator = actMgr.GetActivitiesByUser("nsdev\\administrator");
                //var activitiesTestAdmin = actMgr.GetActivitiesByUser("nsdev\\testadmin");
                //var activitiesTest1 = actMgr.GetActivitiesByUser("nsdev\\test1");
                //var activitiesTest2 = actMgr.GetActivitiesByUser("nsdev\\test2");

                retDT = new DataTable();
                retDT.Columns.Add("Publisher", typeof(string));
                retDT.Columns.Add("PublisherPic", typeof(string));
                retDT.Columns.Add("PublisherLink", typeof(string));
                retDT.Columns.Add("PublisherEmail", typeof(string));
                retDT.Columns.Add("Owner", typeof(string));
                retDT.Columns.Add("OwnerPic", typeof(string));
                retDT.Columns.Add("OwnerLink", typeof(string));
                retDT.Columns.Add("OwnerEmail", typeof(string));
                retDT.Columns.Add("Value", typeof(string));
                retDT.Columns.Add("ActivityDate", typeof(string));
                retDT.Columns.Add("ActivityTime", typeof(string));
                retDT.Columns.Add("ActivityType", typeof(string));
                retDT.Columns.Add("Reserved", typeof(string));

                switch (sType)
                {
                    case SquareActivities.DocAll:
                        retDT = GetTypeAll(activitiesForMe, activitiesByMe, retDT, "Doc");
                        break;
                    case SquareActivities.MemoAll:
                        retDT = GetTypeAll(activitiesForMe, activitiesByMe, retDT, "Memo");
                        break;
                    case SquareActivities.PeopleAll:
                        retDT = GetTypeAll(activitiesForMe, activitiesByMe, retDT, "People");
                        break;
                }

                //retDT = GetActivityDetail((ActivityEventsCollection)activitiesForMe, sType, "For Me", retDT);
                //retDT = GetActivityDetail((ActivityEventsCollection)activitiesByMe, sType, "By Me", retDT);
                //retDT = GetActivityDetail((ActivityEventsCollection)activitiesAdministrator, "By Administrator", retDT);
                //retDT = GetActivityDetail((ActivityEventsCollection)activitiesTestAdmin, "By TestAdmin", retDT);
                //retDT = GetActivityDetail((ActivityEventsCollection)activitiesTest1, "By Test1", retDT);
                //retDT = GetActivityDetail((ActivityEventsCollection)activitiesTest2, "By Test2", retDT);
            }
            return retDT;
        }

        private DataTable GetTypeAll(ActivityEventsCollection activitiesForMe, ActivityEventsCollection activitiesByMe, DataTable retDT,string strFilter)
        {
            foreach (SquareActivities getType in Enum.GetValues(typeof(SquareActivities)))
            {
                if (getType.ToString().Contains(strFilter))
                {
                    if (!getType.ToString().Contains("All"))
                    {
                        retDT = GetActivityDetail((ActivityEventsCollection)activitiesForMe, getType, "For Me", retDT);
                        retDT = GetActivityDetail((ActivityEventsCollection)activitiesByMe, getType, "By Me", retDT);
                    }
                }
            }
            return retDT;
        }

        private DataTable GetActivityDetail(ActivityEventsCollection activites, SquareActivities sType, string strReserved, DataTable dt )
        {
            string actType = string.Empty;
            string actValue = string.Empty;
            string actDate = string.Empty;
            string actTime = string.Empty;
            string[] strPublisher = new string[5];
            string[] strOwner = new string[5];

            bool isSquare = false;

            if (activites != null && activites.Count > 0)
            {
                foreach (var actEvt in activites)
                {
                    XmlDocument xDoc = new XmlDocument();
                    xDoc.LoadXml(actEvt.TemplateVariable);

                    XmlNodeList selectNodes = xDoc.DocumentElement.SelectNodes("//Name");
                    foreach (XmlNode tempNode in selectNodes)
                    {
                        if (tempNode.InnerText == sType.ToString())
                        {
                            actType = tempNode.InnerText;
                            isSquare = true;
                            break;
                        }
                    }

                    if (isSquare)
                    {
                        foreach (XmlNode xNode in xDoc.DocumentElement.ChildNodes)
                        {
                            strPublisher = GetUserInfo(xNode, "Publisher", strPublisher);
                            strOwner = GetUserInfo(xNode, "Owner", strOwner);

                            actValue = xNode.SelectSingleNode("//Value").InnerText;
                            string tempDT = xNode.SelectSingleNode("//PublishDate").InnerText;
                            actDate = tempDT.Substring(0,10);
                            actTime = tempDT.Split('T')[1].Substring(0,8);

                        }
                        dt.Rows.Add(strPublisher[0], strPublisher[2], strPublisher[1], strPublisher[4], strOwner[0], strOwner[2], strOwner[1], strOwner[4], actValue, actDate, actTime, actType, strReserved);
                        isSquare = false;
                    }
                }
            }
            return dt;
        }

        private string[] GetUserInfo(XmlNode uNode, string strUserType, string[] strUser)
        {
            if (uNode.Name == strUserType)
            {
                foreach (XmlNode cNode in uNode.ChildNodes)
                {
                    switch (cNode.Name)
                    {
                        case "Name": strUser[0] = cNode.InnerText; break;
                        case "Href": strUser[1] = cNode.InnerText; break;
                        case "Picture": strUser[2] = cNode.InnerText; break;
                        case "Type": strUser[3] = cNode.InnerText; break;
                        case "Email": strUser[4] = cNode.InnerText; break;
                    }
                }
            }
            return strUser;
        }

        public void SetupActivities(Page page)
        {
        ReDo:
            try
            {
                if (SetActMgr(page))
                {
                    foreach (SquareActivities actType in Enum.GetValues(typeof(SquareActivities)))
                    {
                        if (actMgr.PrepareToAllowSchemaChanges())
                        {
                            if (!actType.ToString().Contains("All"))
                            {
                                SPContext.Current.Web.AllowUnsafeUpdates = true;

                                if (actMgr.ActivityApplications["Square"] == null)
                                {
                                    actApp = actMgr.ActivityApplications.Create("Square");
                                    actApp.Commit();
                                }
                                else
                                {
                                    actApp = actMgr.ActivityApplications["Square"];
                                }

                                squareActType = actApp.ActivityTypes[actType.ToString()];
                                if (squareActType == null)
                                {
                                    squareActType = actApp.ActivityTypes.Create(actType.ToString());
                                    squareActType.ActivityTypeNameLocStringName = "ActivityFeed_" + actType + "_Type_Display";
                                    squareActType.ActivityTypeNameLocStringResourceFile = "SquareRes";
                                    squareActType.IsPublished = true;
                                    squareActType.IsConsolidated = true;
                                    squareActType.AllowRollup = true;
                                    squareActType.Commit();
                                }

                                squareActTemplate = squareActType.ActivityTemplates[ActivityTemplatesCollection.CreateKey(false)];
                                if (squareActTemplate == null)
                                {
                                    squareActTemplate = squareActType.ActivityTemplates.Create(false);
                                    squareActTemplate.TitleFormatLocStringResourceFile = "SquareRes";
                                    squareActTemplate.TitleFormatLocStringName = "ActivityFeed_" + actType + "_Created";
                                    squareActTemplate.Commit();
                                }
                                SPContext.Current.Web.AllowUnsafeUpdates = false;
                            }
                        }
                    }
                }
            }
            catch
            {
                goto ReDo;
            }
        }

        public DataSet actTest(Page page)
        {
            DataSet ds = new DataSet();
            ds.Tables.Add(getTestData(page));
            return ds;
        }

        private DataTable getTestData(Page page)
        {
            DataTable dt = new DataTable();
            dt = new DataTable();
            dt.Columns.Add("actName", typeof(string));
            dt.Columns.Add("actID", typeof(string));

            SetActMgr(page);

            //List<ActivityTypesCollection> actTypeCol = null;
            //actTypeCol = new List<ActivityTypesCollection>(actMgr.ActivityTypes.Count);

            ActivityTypesCollection actTypeCol = actMgr.ActivityTypes;

            foreach (ActivityType actTp in actTypeCol)
            {
                dt.Rows.Add(actTp.ActivityTypeName, actTp.ActivityTypeId.ToString());
            }

            return dt;
        }

        private bool SetActMgr(Page page)
        {
            string pageUser = page.User.Identity.Name;

            if (page.User.Identity.Name.Contains("system"))
            {
                //관리자일 경우 임시로 처리함
                pageUser = System.Environment.UserDomainName + "\\administrator";
            }

            bool bRet = true;
            pm = new UserProfileManager(SPServiceContext.Current);
            curUserProfile = pm.GetUserProfile(pageUser);
            if (curUserProfile != null)
            {
                actMgr = new ActivityManager(curUserProfile, SPServiceContext.Current);
            }

            if (actMgr == null || actMgr.CurrentUserName.Contains("system") || actMgr.CurrentUserName == "")
            {
                bRet = false;
            }
            return bRet;
        }

        //자신의 Activity 입력
        private ActivityEvent GenerateActivityEvent(Page page, string squareValue, SquareActivities sType)
        {
            ActivityEvent activityEvent = null;
            SPUser currentUser = SPContext.Current.Web.CurrentUser;
            HttpContext currentHttpContext = HttpContext.Current;
            try
            {
                Guid siteId = SPContext.Current.Site.ID;
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite aSite = new SPSite(siteId))
                    {
                        using (SPWeb web = aSite.OpenWeb())
                        {
                            SPUser user = web.CurrentUser;
                            web.AllowUnsafeUpdates = true;
                            HttpRequest request = new HttpRequest("", web.Url, "");
                            HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter(CultureInfo.CurrentCulture)));
                            HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
                            WindowsIdentity wi = WindowsIdentity.GetCurrent();
                            typeof(WindowsIdentity).GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(wi, user.LoginName);
                            HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);

                            ActivityTypesCollection actTypeCol = actMgr.ActivityTypes;
                            foreach (ActivityType actTp in actTypeCol)
                            {
                                if (actTp.ActivityTypeName == sType.ToString())
                                {
                                    squareActType = actTp;
                                    break;
                                }
                            }

                            //ActivityApplication activityApplication = actMgr.ActivityApplications["Square"];
                            //squareActType = activityApplication.ActivityTypes[sType.ToString()]; 

                            Entity owner = new MinimalPerson(curUserProfile).CreateEntity(actMgr);
                            Entity publisher = new MinimalPerson(curUserProfile).CreateEntity(actMgr);
                            activityEvent = ActivityEvent.CreateActivityEvent(actMgr, squareActType.ActivityTypeId, owner, publisher);
                            activityEvent.Name = squareActType.ActivityTypeName;
                            activityEvent.ItemPrivacy = (int)Privacy.Public;
                            activityEvent.Owner = owner;
                            activityEvent.Publisher = publisher;
                            activityEvent.Value = squareValue;
                            activityEvent.Commit();

                            web.AllowUnsafeUpdates = false;
                        }
                    }
                });
            }
            finally
            {
                HttpContext.Current = currentHttpContext;
                WindowsIdentity wi = WindowsIdentity.GetCurrent();
                typeof(WindowsIdentity).GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(wi, currentUser.LoginName);
                HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);
            }

            return activityEvent;
        }

        private void MulticastPublishedEvents(List<ActivityEvent> activityEvents)
        {

            if (activityEvents.Count == 0)
                return;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                List<long> publishers = new List<long>();
                foreach (ActivityEvent activityEvent in activityEvents)
                {
                    if (!publishers.Contains(activityEvent.Owner.Id))
                        publishers.Add(activityEvent.Owner.Id);
                }

                Dictionary<long, MinimalPerson> owners;
                Dictionary<long, List<MinimalPerson>> colleaguesOfOwners;
                ActivityFeedGatherer.GetUsersColleaguesAndRights(actMgr, publishers, out owners, out colleaguesOfOwners);

                Dictionary<long, List<ActivityEvent>> eventsPerOwner;
                ActivityFeedGatherer.MulticastActivityEvents(actMgr, activityEvents, colleaguesOfOwners, out eventsPerOwner);

                List<ActivityEvent> eventsToMulticast;
                ActivityFeedGatherer.CollectActivityEventsToConsolidate(eventsPerOwner, out eventsToMulticast);

                int startIndex = 0;
                while (startIndex + actMgr.MaxEventsPerBatch < eventsToMulticast.Count)
                {
                    ActivityFeedGatherer.BatchWriteActivityEvents(eventsToMulticast, startIndex, actMgr.MaxEventsPerBatch);
                    startIndex += actMgr.MaxEventsPerBatch;
                }
                ActivityFeedGatherer.BatchWriteActivityEvents(eventsToMulticast, startIndex, eventsToMulticast.Count - startIndex);

            });
        }
    }
}
